import { ConfigManager } from '@/api/config/ConfigManager';
import { GraphShapeUtil } from './GraphShapeUtil';
/* eslint-disable @typescript-eslint/no-use-before-define */
import {
  treeForEach,
  TreeNode, uniqueArr,
  handleExcelData,
  handleReqifData,
  handleRenameTableName
} from '@/util/common';
import { emitter } from 'src/util/Emitter';
import localFile from 'src/util/localFile/index';
import graphUtil from './graphUtil';
import { portal as simulation } from 'src/components/Simulation/Simulation.vue';
import { portal as attributeDetail } from 'components/Attribute/modals/AttributeDetail.vue';
import { portal as chooseElement } from 'src/components/common/ChooseElement.vue';
import { portal as elementMatrix } from 'src/components/common/ElementMatrix.vue';
import { portal as displayPartsPorts } from 'src/components/common/Modal/DisplayPartsPorts.vue';

import { portal as selectValue } from 'src/components/Attribute/modals/SelectValue.vue';
import { portal as selectMutiple } from 'src/components/Attribute/modals/SelectMutiple.vue';
import { portal as displayElement } from 'src/components/common/DisplayElement.vue';
import { portal as checkLoading } from 'src/components/Project/modals/SaveLoading.vue';
import treeUtil from 'src/components/ModelTree/treeUtil';
import { getStyleObj, getStyleStr } from 'src/util/common';
import ResizeUtil from './resizeUtil';
import { GraphNodeUtil } from './GraphNodeUtil';
import { MofModelRepositoryHelper, SysMLUtilHelper } from 'src/api/sysml-imports';
import { portal as wizardAttributeDetail } from 'src/components/Attribute/modals/WizardAttributeDetail.vue';

import { propertyMenuUtil } from './PropertyMenuUtil';
import { graphHelper } from '@/api/GraphHelper';
import { portal as unablecheckInPackageModal } from 'src/components/cooperation/checkIn/unablecheckInPackageModal.vue';
import { portal as syncReqModal } from '@/components/projectReq/syncReq/modals/SyncReq.vue';

import { PropertyUtil } from "components/Attribute/comps/PropertyUtil";
import graphNodeStatusFresher  from "src/components/cooperation/GraphNodeStatusFresher";

import submitUpdate from "src/components/cooperation/submitUpdate/submitUpdate";
import updateModel from "src/components/cooperation/submitUpdate/UpdateModel";

import { LocalFileService } from "@/util/localFile/LocalFileService";
import { API } from '@/constants/api';
import { GraphNodeStatus, GraphNodeType } from './../../constants/Enums';
import { behaviors } from './behaviors/index';
import { SaveType } from '@/util/BackupManager';

//// import  Confirm from 'src/components/common/Modal/Confirm.vue';
//// action schema
/**
 * {
 * name:String，
 * onShapeMenuClick:Function,
 * bindKey:String
 *
 * }
 */

//// 查找符合条件的shape
function findShape(shape) {
  const children = shape.children;
  let currentChildren = null;
  for (let i = 0; i < children.length; i++) {
    const child = children[i];
    const childShape = { children: child.children, container: child.container, origin: child, parent: shape };
    if (i === 0) {
      shape.child = childShape;
    } else if (currentChildren) {
      currentChildren.sibling = childShape;
    }
    currentChildren = childShape;
  }
}

//// 递归树节点
function searchTree(shape, condition) {
  //// console.log('diagram', shape);
  let found = false;
  let fakeShape = { children: shape.children, container: shape.container, origin: shape, parent: null, sibling: null, child: null };
  while (fakeShape && !found ) {
    findShape(fakeShape);
    //// console.log('fakeShape', fakeShape);
    if (condition(fakeShape.container)) {
      found = true;
      break;
    }
    if (fakeShape.child) {
      fakeShape = fakeShape.child;
    } else {
      while (fakeShape) {
        if (fakeShape.sibling) {
          fakeShape = fakeShape.sibling;
          break;
        } else {
          fakeShape = fakeShape.parent;
        }
      }
    }
  }

  return fakeShape && fakeShape.origin;

}

/**
 *
 * @param node GraphNode
 * @param connectorShape 连线的shape
 * @param shape 当前元素的shape
 * @returns Boolean
 */
function isSameConnector(node, connectorShape, shape) {
  if (node === connectorShape) {
    let type = '';
    if (connectorShape.getTargetConnector().getGraphElement() === shape.container) {
      type = 'target';
    } else {
      type = 'source';
    }
    for (let i = 0; i < node.childLeafElement.length; i++) {
      const currentShape = node.childLeafElement[i];
      const targetShape = currentShape.targetSingleLeaf;
      const sourceShape = currentShape.sourceSingleLeaf;
      if (type === 'target' && targetShape === shape) {
        return true;
      }
      if (type === 'source' && sourceShape === shape) {
        return true;
      }
    }
  }
  return false;
}

export class Actions {
  actionMap:Map<string, Action> = new Map()
  events:{[prop:string]:Function}={}

  constructor(){
    this.createActionMap();
    //// this.createEvents();

  }
  createActionMap(){
    this.actionMap = new Map();

  }
  createEvents(){
    this.actionMap.forEach((action:Action) => {
      if (!action.bindKey) return;
      this.events[action.bindKey] = () => {

        //// 目前只做了画布的事件监听
        if (!app.activeGraphTab || !app.activeGraphTab.diagramType) return;
        action.onKeyboardEvent(app.activeGraphTab.graph);

      };
    });
  }
  addKeyboardListener(){
    emitter.onBatch(this.events);

  }
  removeKeyBordListener(){
    emitter.offBatch(this.events);

  }
  addAction(action:Action){
    this.actionMap.set(action.keyName, action);

  }
  getAction(keyName:string):Action{
    return  this.actionMap.get(keyName);
  }

}

export const actions = new Actions();

interface Action {
  /**
   * action唯一键值，必须有
   */
  keyName:string

  /**
   * action描述，非必须
   */
  desc:string

  /**
   * action需要绑定的键盘事件 ，中横线分割
   */
  bindKey:string
  /**
   * 在画布上触发action的的入口方法
   * @param graph
   * @param shape
   * @param menuItem
   */
  onShapeMenuClick?(graph:Graph, shape?:UmlShape, menuItem?:TreeNode):void

  /**
   * 键盘事件触发action时的入口方法
   * @param graph
   */
  onKeyboardEvent?(graph: Graph): void

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick?(graphNode: GraphNode, menuItem: TreeNode): void

  /**
   *
   * @param menuItem
   */
  onSysMenuClick?(menuItem: TreeNode): void

  /**
   * 核心方法，用于跳过前置步骤，直接调用action
   * @param item
   * @param option
   */
  run?(item: any, option?: any): any

}

export interface SetPropertyAction extends Action {
  /**
   * 设置instance的右上角图标
   * @param shape target的shape
   * @param graphNode 源的node
   */
  setInstanceImage?(shape: UmlShape, graphNode: GraphNode): void
}

export class RemoveShapeAction implements Action {
  keyName = 'removeShape'
  desc = '从画布上移除'
  bindKey = 'Delete'

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape, graph.diagramShape);
    app.$bus.emit('fresh-graph');
  }

  /**
   * 删除图形时要把相关联的线图形也删除，线也可能有关联的线
   */
  remove(shape: UmlShape, diagramShape: UmlShape, removedIds: string[] = []) {
    const relateEdgeShapes = diagramShape.children.filter(i => i.sourceSingleLeaf?.id === shape.id || i.targetSingleLeaf?.id === shape.id);
    relateEdgeShapes.forEach(shape => {
      if (removedIds.includes(shape.id)) return;
      removedIds.push(shape.id);
      this.remove(shape, diagramShape, removedIds);
    });

    shape.remove();

  }

  run(shape: UmlShape, diagramShape: UmlShape) {
    if (shape.owner == null) return; //// 不允许删除根图形
    let removeType = 0;
    if (shape.graphNode.model) {
      removeType = ConfigManager.getRemoveShapeConfig(shape.graphNode.model.getClassName());
    }

    //// 删除图形的时候可能需要删除模型
    if (removeType === 1){
      (actions.getAction('removeModel') as RemoveModelAction).run(shape.container);

    } else if (removeType === 2 && shape.container.childLeafElement.length <= 1){
      (actions.getAction('removeModel') as RemoveModelAction).run(shape.container);

    } else {
      this.remove(shape, diagramShape);

    }

    app.$bus.emit('project-modified');
  }

  onKeyboardEvent(graph: Graph) {
    if (graph.isEditing()) return; //// 编辑中不能删除
    const selection = graph.getSelectionModel();
    const cell = selection.cells[0];
    console.log(selection.cells);
    if (!cell) return;
    //// 找到一级元素
    const topCells = selection.cells.filter(cell => !selection.cells.find(i => graphUtil.isAncestor(i, cell)));
    const topMainShapes: UmlShape[] = topCells.map(cell => GraphShapeUtil.getMainShape(cell.umlShape)).filter(i => i.owner != null);
    topMainShapes.forEach(shape => {
      this.run(shape, graph.diagramShape);

    });

    //// const shape = cell.umlShape;
    //// const mainShape = graphUtil.getMainShape(shape);
    //// this.run(mainShape, graph.diagramShape);

    app.$bus.emit('fresh-graph');

  }

}

actions.addAction(new RemoveShapeAction());

function handleQuicklyCreatDiagram(menuItem, graphNode?: GraphNode) {
  if (!graphNode) return;
  //// let portsAndProperties = graphNode.getAllPortOrProperty();
  let portsAndProperties = graphNode.getAllAttributes().toArray();
  console.log('portsAndProperties', portsAndProperties);
  if (portsAndProperties) {
    displayPartsPorts.popup({
      partNodes: portsAndProperties,
      blockNode: graphNode
    }).then((data: GraphNode[]) => {
      let portCount = 0;
      let partHeightCount = 40;

      let diagramNode = (actions.getAction('openCreateDiagram') as OpenCreateDiagramAction).run(graphNode, menuItem);

      let shape = diagramNode.umlDiagramFrame;
      data.forEach((graphNode) => {
        console.log('checked', graphNode);
        const typeName = graphNode.getTypeName();
        //// port逻辑
        const shapes = shape.addChildShape(typeName, graphNode, shape, shape);
        if (!shapes || !shapes[0]) {
          throw new Error('create shape error');
        }
        if (typeName.includes('Port')) {
          portCount += 1;
          console.log("portCount", portCount);
          shapes[0].box.boxY = portCount * 40;
          shapes[0].box.boxX = -10;
          shapes[0].box.portDirection = 'left';
        } else { ////  parts 逻辑
          shapes[0].box.boxY = partHeightCount;
          shapes[0].box.boxX = 100;
          partHeightCount = partHeightCount + shapes[0].box.height + 10;
        }
      });
    });

    app.$bus.emit('fresh-graph');
  }

  app.$bus.emit('project-modified');
}

export class CreateIDBDiagramAction implements Action {
  keyName = 'createIDBDiagram'
  desc = '快速创建IBD'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape.container);
    app.$bus.emit('fresh-graph');
  }

  run(graphNode: GraphNode) {
    const menuItem = {
      type: 'diagram',
      label: '内部模块图',
      value: 'SysMLInternalBlockDiagram'
    };
    handleQuicklyCreatDiagram(menuItem, graphNode);
  }
}

actions.addAction(new CreateIDBDiagramAction());

export class CreatePARDiagramAction implements Action {
  keyName = 'createPARDiagram'
  desc = '快速创建PAR'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape.container);
    app.$bus.emit('fresh-graph');
  }

  run(graphNode: GraphNode) {
    const menuItem = {
      type: 'diagram',
      label: '参数图',
      value: 'SysMLParametricDiagram'
    };
    handleQuicklyCreatDiagram(menuItem, graphNode);
  }
}

actions.addAction(new CreatePARDiagramAction());

export class NavigationAction implements Action {
  keyName = 'navigation'
  desc = '导航'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape: UmlShape, menuItem: TreeNode) {
    console.log(this.keyName, this.desc);
    this.run(menuItem.graphNode);
  }

  run(diagramNode: GraphNode) {
    (actions.getAction('openDiagram') as OpenDiagramAction).run(diagramNode);

    //// app.$bus.emit('project-modified');
  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    this.run(menuItem.graphNode);

  }

}

actions.addAction(new NavigationAction());

export class ShowWizardAttributeAction implements Action {
  keyName = 'ItemFlow'
  desc = '显示itemflow弹框'
  bindKey = ''

  run(diagramNode: GraphNode) {
    //// (actions.getAction('openDiagram') as OpenDiagramAction).run(diagramNode);
    if (this.wizardAttributeDetailVisible) return;
    this.wizardAttributeDetailVisible = true;
    wizardAttributeDetail
      .popup()
      .then(({ tableData, context }) => {
        tableData.forEach((tableCell, index) => {
          console.log(index, tableCell.rowData.value);
        });

        //// 在这种新建和update合一的模式下
        //// 新建则新建一个element ，update则，选中列表中的一个element，
        //// 其实这个列表是可以先生成的，不需要选择

        //// 可能是add或者update
        //// 创建itemflow  ，后端将其与association相连
        //// from A to B  ,所选线的A,B =>必须有个输入点
        //// 如果是connector 表示没有方向
        //// let selectedElement = proxy.projects.get(proxy.activeProject).ui.selectElement;
        //// let connectorEdge = selectedElement.diagramElement.toArray()[0];
        //// let sourceShape = connectorEdge.source;
        //// let targetShape = connectorEdge.target;
        //// const res = graphUtil.post('/graph/edge/add', {
        ////   typeName: 'ItemFlow',
        ////   diagram: selectedElement,
        ////   sourceShape,
        ////   targetShape
        //// });
        //// 那两选项是固定的
        let selectedElement = app.selectedElement;
        let allItems = SysMLUtilHelper.getItemFlowList(selectedElement).toArray();

        let connectorEdge = selectedElement;
        let sourceElement = connectorEdge.getSource();
        let targetElement = connectorEdge.getTarget();
        if (tableData[1].rowData.value == 1) {
          //// 表示两个方向
          sourceElement = connectorEdge.getTarget();
          targetElement = connectorEdge.getSource();
        }

        let ItemFlowElement = null;
        if (tableData[0].rowData.value == 0) {
          //// 新建
          //// ItemFlowElement = modelApi.createconnectorship({
          ////   typeName: 'ItemFlow',
          ////   parentElement: selectedElement,
          ////   sourceElement,
          ////   targetElement
          //// });

          //// ItemFlowElement = sourceElement.addChildEdge('ItemFlow', sourceElement, targetElement, app.activeProjectId);
          ItemFlowElement = (actions.getAction('openCreateOutRelation') as OpenCreateOutRelationAction).run('ItemFlow', {
            source: sourceElement,
            target: targetElement
          });
          console.log({ ItemFlowElement });

        } else {
          //// 编辑
          ItemFlowElement = SysMLUtilHelper.getItemFlowList(
            selectedElement
          ).toArray()[tableData[0].rowData.value - 1];
        }
        console.log(tableData[2].rowData.value, ItemFlowElement);

        //// console.log('这个update 可能有问题,新建为空时 对象和多选后对象不同??');
        //// 这个update 可能有问题
        if (tableData[2].rowData.value[0]) {
          SysMLUtilHelper.PropertyOperation.propertyModifier.updateConveyedForInformationFlow(
            [tableData[2].rowData.value[0].graphNode],
            ItemFlowElement
          ); //// modearr

        }

        if (tableData[3].rowData.value?.graphNode) {
          PropertyUtil.updatePropertyByName(
            ItemFlowElement,
            "ItemProperty",
            tableData[3].rowData.value.graphNode.model
          );
        }

        const selection = app.activeGraphTab.graph.getSelectionModel();
        const cell = selection.cells[0];
        if (!cell) return;
        const shape = cell.umlShape;

        let styleObj = getStyleObj(shape.box.style);

        //// 新建
        if (tableData[0].rowData.value == 0) {
          if (tableData[1].rowData.value === 1) {
            styleObj.startArrow = 'block';
          } else {
            styleObj.endArrow = 'block';
          }
        } else { //// 编辑
          //// 获取allItems 的方向 如果不是全部都有那么方向只有一种
          let allItems = SysMLUtilHelper.getItemFlowList(selectedElement).toArray();
          let directionAtoB = -1;
          let directionBtoA = -1;
          allItems.map((currentItemFlow, b) => {
            if (b != tableData[0].rowData.value - 1) {
              //// 计算编辑itemflow的方向
              if (currentItemFlow.informationSource.toArray()[0].id === connectorEdge.getSource().id) {
                directionAtoB = 0;
              } else {
                directionBtoA = 0;
              }
            }
          });

          if (tableData[1].rowData.value === 1) {
            directionBtoA = 0;
          } else {
            directionAtoB = 0;
          }

          if (directionAtoB == 0 && directionBtoA == 0) {
            styleObj.startArrow = 'block';
            styleObj.endArrow = 'block';
          }

          if (directionAtoB == -1 && directionBtoA == 0) {
            styleObj.startArrow = 'block';
            styleObj.endArrow = 'none';
          }

          if (directionAtoB == 0 && directionBtoA == -1) {
            styleObj.endArrow = 'block';
            styleObj.startArrow = 'none';
          }

        }

        console.log(tableData[2].rowData.value, { tableData, styleObj, ItemFlowElement });

        shape.box.style = getStyleStr(styleObj);

        context.$bus.emit('model-add');
        context.$bus.emit('fresh-graph');
      })
      //// connectorEdge 对这个的itemflow进行渲染、
      .catch(e => e && console.error(e))
      .finally(() => (this.wizardAttributeDetailVisible = false));

    //// app.$bus.emit('project-modified');
  }

  wizardAttributeDetailVisible = false

  onPopupMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    this.run(menuItem.graphNode);
  }

}

actions.addAction(new ShowWizardAttributeAction());

export class ShowStereotypeAction implements Action {
  keyName = 'showStereoType'
  desc = '构造型'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape);
    app.$bus.emit('fresh-graph');
  }

  run(shape: UmlShape) {

    //// app.$bus.emit('project-modified');
  }
}

actions.addAction(new ShowStereotypeAction());

export class RemoveModelAction implements Action {
  keyName = 'removeModel'
  desc = '从模型和画布上删除'
  bindKey = 'ctrl-d'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
    //// 如果有模型删除模型，如果没有模型则删除图形
    if (shape.container && shape.container.getTypeName() != 'Containment') {
      const canRemove = this.checkCanRemove([shape.container]);
      if (!canRemove) return;
      this.run(shape.container);
    } else {
      shape.remove();
    }
    app.$bus.emit('fresh-graph');
    app.$bus.emit('project-modified');

  }

  run(graphNode: GraphNode) {
    //// 节点删除时，节点的图形也会被删除
    //// 节点的图形删除时，如果flow的元素父图形，需更新其主absolute元素
    const needReflowShapes = [];
    graphNode.childLeafElement.forEach(leaf => {
      if (leaf.box.position === 'flow') {
        needReflowShapes.push(graphUtil.getFirstNotInitMainShape(leaf));

      }
    });
    const arr = uniqueArr(needReflowShapes);

    graphNode.remove();
    arr.forEach(shape => {
      ResizeUtil.updateAutoFlow(shape);
    });
    app.$bus.emit('model-delete', { id: graphNode.id });
    let copyedNodeId = app.activeProject.ui.copyedNodeId;
    if (copyedNodeId === graphNode.id) {
      app.activeProject.ui.copyedNodeId = '';
    }
  }

  onKeyboardEvent(graph: Graph) {
    window.event.preventDefault();
    const selection = graph.getSelectionModel();
    const cell = selection.cells[0];
    if (!cell) return;
    const topCells = selection.cells.filter(cell => !selection.cells.find(i => graphUtil.isAncestor(i, cell)));
    const topMainShapes: UmlShape[] = topCells.map(cell => GraphShapeUtil.getMainShape(cell.umlShape)).filter(i => i.owner != null);
    const canRemove = this.checkCanRemove(topMainShapes.map(shape => shape.container).filter(Boolean));
    if (!canRemove) return;
    topMainShapes.forEach(shape => {
      if (shape.container && shape.container.getTypeName() != 'Containment') {
        this.run(shape.container);
      } else {
        shape.remove();
      }
    });
    app.$bus.emit('fresh-graph');
    app.$bus.emit('project-modified');
    //// const shape = cell.umlShape;
    //// this.onShapeMenuClick(graph, shape);

  }

  async onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    const canRemove = this.checkCanRemove([graphNode]);
    if (graphNode.status === GraphNodeStatus.FROM_PROFILE) {
      const result = await app.$Confirm.popup({
        title: '删除扩展包',
        subTitle: '确定删除？',
        content: '删除扩展包后，项目中所有与此扩展包中元素相关的关系将被删除。',
        okText: '删除并重启',
        status: 'warn',
        cancelText: '取消'
      })
        .then(res => {
          return true;
        })
        .catch(() => {
        });
      if (!result) return;
    }
    if (!canRemove) return;
    this.run(graphNode);
    app.$bus.emit('fresh-graph');
    app.$bus.emit('project-modified');
    if (graphNode.status === GraphNodeStatus.FROM_PROFILE) {
      localFile.reloadProject(app.activeProject)
        .then((project) => {
          app.proxy.projects.set(project.config.id, project);
          localFile.switchToProject(project);
          app.$messageBox.success({ text: '重载成功' });
        });
    }
  }

  /**
   * 检查元素是否可删除
   * @param graphNodes
   * @returns
   */
  checkCanRemove(graphNodes: GraphNode[]): boolean {
    if (app.activeProject.config.online) {
      const existDisabledNode = graphNodes.find(i => {
        return i.disabled || (i.container.disabled && GraphNodeUtil.isOrIsInstanceOf(i.container.getTypeName(), 'Package') );
      });
      if (existDisabledNode){
        //// app.tipError({ status: 5009 });
        app.$messageBox.error({
          text: '删除失败',
          duration: 10
        });
        return false;
      }
    }
    return true;
  }
}

actions.addAction(new RemoveModelAction());

export class EscAction implements Action {
  keyName = 'Escape'
  desc = 'Escape'
  bindKey = 'Escape'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);

  }

  onKeyboardEvent(graph: Graph) {

  }

}

actions.addAction(new EscAction());

export class CopyAction implements Action {
  keyName = 'copy'
  desc = '复制'
  bindKey = 'ctrl-c'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);

  }

  onKeyboardEvent(graph: Graph) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    //// this.run(graphNode);
    //// app.$bus.emit('fresh-graph');
    console.log({ graphNode, menuItem });

  }
}

actions.addAction(new CopyAction());

export class CopyNodeAction implements Action {
  keyName = 'copyNode'
  desc = '复制'
  bindKey = 'ctrl-i'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);

  }

  onKeyboardEvent(graph: Graph) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    console.log({ graphNode, menuItem });
    app.activeProject.ui.copyedNodeId = graphNode.id;
  }
}

actions.addAction(new CopyNodeAction());

export class CutAction implements Action {
  keyName = 'pasteNode'
  desc = '粘贴'
  bindKey = 'ctrl-x'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
  }

  onKeyboardEvent(graph: Graph) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    console.log({ graphNode, menuItem });
    let sourceNode = null;
    if (app.activeProject.ui.copyedNodeId) {
      sourceNode = graphHelper.getGraphNodeById(app.activeProject.ui.copyedNodeId, app.activeProjectId);
    } else {
      return;
    }
    const result = SysMLUtilHelper.copyElement(app.activeProjectId, sourceNode.model, graphNode.model);
    const newTitle = GraphNodeUtil.getNewChildNodeName(graphNode, result.title);
    result.updateName(newTitle);
    console.log('result', result, graphNode);
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new CutAction());

export class ImportRequirementExcelAction implements Action {
  keyName = 'importRequirementExcel'
  desc = '导入Excel'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
  }

  onKeyboardEvent(graph: Graph) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    localFile.openExcel('excel')
      .then(res => {
        //// console.log('res', res);
        const name = res.name.split('.')[0];
        const requirements = handleExcelData(res);
        const packageNode = graphNode.importExcel(
          requirements
        );
        handleRenameTableName(packageNode, name);
        app.$bus.emit('project-modified');
      })
      .catch(err => console.log(err));
  }
}

actions.addAction(new ImportRequirementExcelAction());

export class ImportRequirementReqIFAction implements Action {
  keyName = 'importRequirementReqIF'
  desc = '导入Regif'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
  }

  onKeyboardEvent(graph: Graph) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    localFile.openReqif('reqif')
      .then(res => {
        //// console.log('res', res);
        const name = res.name.split('.')[0];
        const requirements = handleReqifData(res);
        const packageNode = graphNode.importReqIf(
          requirements
        );
        handleRenameTableName(packageNode, name);
        app.$bus.emit('project-modified');
      })
      .catch(err => console.log(err));
  }
}

actions.addAction(new ImportRequirementReqIFAction());

export class PasteAction implements Action {
  keyName = 'cut'
  desc = '剪切'
  bindKey = 'ctrl-x'

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
  }

  onKeyboardEvent(graph: Graph) {
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new PasteAction());

export class SaveAction implements Action {
  keyName = 'save'
  desc = '保存'
  bindKey = 'ctrl-s'

  onShapeMenuClick(graph: Graph) {
    console.log(this.keyName, this.desc);
  }

  onKeyboardEvent(graph: Graph) {
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new SaveAction());

export class ShowAttributeAction implements Action {
  keyName = 'showAttribute'
  desc = '属性'
  bindKey = ''

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    if (!shape.container) return;

    this.run(shape.container);

  }

  run(graphNode: GraphNode) {
    app.ui.selectedElement = graphNode;
    attributeDetail.popup({}, { single: true }); //// 单弹窗模式

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    this.run(graphNode);

  }
}

actions.addAction(new ShowAttributeAction());

export class SelectOnTreeAction implements Action {
  keyName = 'selectOnTree'
  desc = "树上高亮"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    if (!shape.container) return; //// 可能没有模型
    this.run(shape.container);
    //// app.ui.selectedElement = shape.container;
  }

  run(graphNode: GraphNode, option: { scroll: boolean } = { scroll: true }) {
    if (!app.ui) return;
    app.ui.selectedElement = graphNode;
    graphNode.expandParentNode();
    if (option) {
      if (option.scroll) {
        setTimeout(() => {
          const dom = document.getElementById(graphNode.id);
          if (dom) {
            dom.scrollIntoView({ behavior: "smooth", block: "center", inline: "nearest" });

          }
        }, 100);
      }

    }

  }

  onKeyboardEvent(graph: Graph) {
    const selectedCells = graph.getSelectionModel().cells;
    const graphNode: GraphNode = selectedCells[0]?.umlShape?.container;
    this.run(graphNode);

  }

}

actions.addAction(new SelectOnTreeAction());
export class ShowRelationEdgeAction implements Action {
  keyName = 'showRelationEdge'
  desc = "显示关系连线"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape);
  }

  run(shape: UmlShape) {
    let connectors = shape.container.getAnchorages();
    console.log('shape', shape);
    let diagram = shape.getDiagramLeaf();
    console.log('connectors', connectors, diagram, shape);
    //// connectors = connectors.filter(connector => connector.getGraphEdge().getTypeName() !== 'Containment');
    //// connectors = connectors.filter(connector => !diagram.children.some(umlshape => umlshape.container === connector.getGraphEdge()));
    //// console.log('connectors2', connectors);
    if (connectors.length > 0) {
      connectors.forEach((connector) => {
        let targetShape: UmlShape, sourceShape: UmlShape;
        console.log('connector.graphEdge.getTypeName()', connector.graphEdge.getTypeName());
        if (connector.graphEdge.getTypeName() === 'Anchor') return;
        //// 过滤已存在的connector
        //// if (searchTree(diagram, node => node === connector.getGraphEdge())) return;

        //// 判断是否是同一连线
        const connectorShape = connector.getGraphEdge();
        if (searchTree(diagram, node => {
          return isSameConnector(node, connectorShape, shape);
        })) return;

        if (connector.graphEdge.getTypeName() === 'Satisfy') { //// Satisfy的sourceShape需递归查找
          targetShape = diagram.children.find(item => connector.getGraphEdge().getTargetConnector().getGraphElement() === item.container);
          sourceShape = searchTree(diagram, node => node === connector.getGraphEdge().getSourceConnector().getGraphElement());
        } else {
          targetShape = diagram.children.find(item => connector.getGraphEdge().getTargetConnector().getGraphElement() === item.container);
          sourceShape = diagram.children.find(item => connector.getGraphEdge().getSourceConnector().getGraphElement() === item.container);
        }
        console.log('searchedShape', targetShape, sourceShape);

        if (targetShape && targetShape.container.id === shape.container.id) { //// 当两个shape来自同一个node时
          targetShape = shape;
        }
        if (sourceShape && sourceShape.container.id === shape.container.id) { //// 当两个shape来自同一个node时
          sourceShape = shape;
        }

        //// console.log('targetShape', diagram, targetShape, sourceShape);
        if (targetShape != null && sourceShape != null){
          let edge = diagram.addEdgeShape(null, null, diagram, connector.getGraphEdge(), diagram, sourceShape, targetShape)[0];
          edge.sourceLabel && (edge.sourceLabel.box.initX = 0.9);
          edge.targetLabel && (edge.targetLabel.box.initX = -0.9);
          behaviors.get('SysMLInternalBlockDiagram').displaySatisfyPoint(edge, edge.getTypeName(), diagram, sourceShape);
          ResizeUtil.initShape(edge);
        }
      });
      app.$bus.emit("fresh-graph");
    }
  }

}

actions.addAction(new ShowRelationEdgeAction());

export class showInnerItemAction implements Action {
  keyName = 'showInnerItem'
  desc = "显示内部元素"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    this.run(shape);
  }

  run(shape: UmlShape) {
    let nodes = shape.children.map(node => node.graphNode);
    let allChildren = shape.container.getAllAttributes().toArray();
    const linkedType = PropertyUtil.getNodePropertyValue(shape.graphNode, 'Type');
    if (linkedType) { //// 获取关联类型的元素
      const linkedTypeNode = graphHelper.getGraphNodeById(linkedType.id, app.activeProjectId);
      let linkedTypeAttributes = linkedTypeNode.getAllAttributes().toArray();
      linkedTypeAttributes = linkedTypeAttributes.filter(item => !allChildren.includes(item));
      allChildren = allChildren.concat(linkedTypeAttributes);
    }
    let existChildren = [];
    let children = [];
    console.log('allChildren', allChildren);
    if (shape.container.getTypeName() === 'Package') {
      shape.container.children.forEach(item => {
        if (!allChildren.includes(item)) {
          allChildren.push(item);
        }
      });
    }

    allChildren.forEach(node => {
      //// console.log(node.getType());
      if (node.getType() === 'node') {
        if (!nodes.includes(node)) {
          children.push(node);
        } else {
          existChildren.push(node);
        }
      }
    });
    let comY = 50;
    //// console.log('comY1', comY, shape);
    let height = 50;
    let width = shape.box.width;
    allChildren.forEach(child => { //// 计算shape的高度
      if (child.getTypeName().includes('Port')) { //// 端口高度为16， 间隔20
        height += 36;
      } else { //// 其他类型高度为30， 间隔20
        height += 50;
      }
    });
    existChildren.forEach(child => {
      if (child.getTypeName().includes('Port')) {
        comY += 36;
      } else {
        comY += 50;
      }
    });
    shape.box.boxHeight = height;
    //// console.log('height', height);
    ResizeUtil.updateBoundsByBox(shape);

    const CONFIG = {
      horizontalSpacing: 20,
      verticalSpacing: 100,
    };

    children.reduce((accumulator, node, currentIndex) => {
      //// console.log('123', node.getTypeName(), node, shape.owner, shape);
      const shapes = shape.addChildShape(node.getTypeName(), node, shape.graphFrame, shape)[0];
      console.log('shapes', shapes);
      ResizeUtil.initShape(shapes, 0, accumulator);
      //// height += shapes.box.height + CONFIG.horizontalSpacing;
      width = Math.max(width, shapes.box.width);
      //// console.log('accumulator', accumulator, height);
      if (currentIndex === children.length - 1) {
        console.log('expandParentSize');
        ResizeUtil.expandParentSize(shapes);
      }
      return accumulator + shapes?.box.height + CONFIG.horizontalSpacing;
    }, comY);

    shape.box.boxWidth = width;
    ResizeUtil.updateAutoFlow(shape);
    app.$bus.emit('fresh-graph');
  }
}

actions.addAction(new showInnerItemAction());

class ShowInternalPortAction implements Action {
  keyName = 'showInternalPort'
  desc = "显示内部端口"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    this.run(shape);
  }

  run(shape: UmlShape) {
    //// 可以获取泛化元素的端口
    let ports = shape.graphNode.getAllAttributes().toArray().filter(node => node.getTypeName().includes('Port'));
    const linkedType = PropertyUtil.getNodePropertyValue(shape.graphNode, 'Type');
    if (linkedType) { //// 获取关联类型的元素
      const linkedTypeNode = graphHelper.getGraphNodeById(linkedType.id, app.activeProjectId);
      let linkedTypeAttributes = linkedTypeNode.getAllAttributes().toArray();
      linkedTypeAttributes = linkedTypeAttributes.filter(item => !ports.includes(item) && item.getTypeName().includes('Port'));
      ports = ports.concat(linkedTypeAttributes);
    }
    let comY = 50;
    const CONFIG = {
      horizontalSpacing: 20,
      verticalSpacing: 100,
    };
    shape.box.boxHeight = Math.max(shape.box.boxHeight, ports.length * (16 + 20) + comY);
    ResizeUtil.updateBoundsByBox(shape);
    const childrenIdObj = {}; //// 存取已存在的children的id
    //// console.log('shape.children', shape.children);
    if (shape.children) {
      shape.children.forEach(child => {
        if (child.graphNode.getTypeName().includes('Port')) {
          childrenIdObj[child.graphNode.id] = true;
          comY += 50;
        }
      });
    }
    ports.reduce((accumulator, port, currentIndex) => {
      if (!childrenIdObj[port.id]) { //// 放置元素重复
        const portShape = shape.addChildShape(port.getTypeName(), port, shape.owner, shape)[0];
        ResizeUtil.initShape(portShape, shape.box.boxWidth, accumulator);

        return accumulator + portShape?.box.height + CONFIG.horizontalSpacing;
      } else {
        return accumulator;
      }

    }, comY);
    app.$bus.emit('fresh-graph');
  }
}

actions.addAction(new ShowInternalPortAction());

export class ShowRelatedElementAction implements Action {
  keyName = 'showRelatedElement'
  desc = "显示关联元素"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    this.run(shape);
  }

  /**
   * 先判断线是否已经存在.
   * 如果存在就直接return
   * 不存在就判断目标节点是否在画布上
   * 在的话 就创建连线
   */
  run(shape: UmlShape) {
    let connectors = shape.container.getAnchorages();
    let diagram = shape.getDiagramLeaf();
    //// connectors = connectors.filter(node => node.graphEdge.getTypeName() !== 'Containment');
    if (connectors.length > 0) {
      let typeNameList = connectors.map(node => {
        return node.graphEdge.getTypeName();
      });
      typeNameList = typeNameList.filter(type => {
        return type !== 'Anchor';
      });
      let typeNames = Array.from(new Set(typeNameList));
      interface Element {
        element: GraphNode;
        target: GraphNode;
        source: GraphNode;
      };

      type ConnentType = GraphConnector & Element;
      displayElement
        .popup({
          name: shape.container.title,
          relation: typeNames
        })
        .then(({ typeNameList, direction }) => {
          console.log("connectors返回的结果", typeNameList, direction);
          connectors = connectors.filter(node => typeNameList.includes(node.getGraphEdge().getTypeName()));
          //// console.log('connectors1', connectors);
          connectors = connectors.filter((connector: ConnentType) => {
            const target = connector.getGraphEdge().getTargetConnector().getGraphElement();
            const source = connector.getGraphEdge().getSourceConnector().getGraphElement();
            connector.target = target;
            connector.source = source;
            if (direction !== 'BOTH') {
              if (direction === 'FROM') {
                connector.element = source;
                return target === shape.container;
              }
              if (direction === 'TO') {
                connector.element = target;
                return source === shape.container;
              }
            } else {
              connector.element = target === shape.container ? source : target;
              return true;
            }

          });
          console.log('connectors3', connectors);
          const CONFIG = {
            horizontalSpacing: 20,
            verticalSpacing: 100,
          };
          const totalWidth = connectors.reduce((accumulator, connector: ConnentType, currentIndex) => {
            return accumulator + connector?.graphElement?.childLeafElement[0]?.bounds?.width + CONFIG.horizontalSpacing;
          }, 0);

          //// let totalWidth = 0;
          //// for (let i = 0; i < connectors.length; i++) {
          ////   const connector = connectors[i];
          ////   const element = (connector as ConnentType).element;
          ////   if (element.getTypeName() === 'InstanceSpecification' && (element.model && element.model.name === null)) {
          ////     continue;
          ////   } else {
          ////     totalWidth = element?.childLeafElement[0]?.bounds?.width + CONFIG.horizontalSpacing;
          ////     break;
          ////   }
          //// }
          let startX = shape.box.boxX + (shape.box.width / 2) - (totalWidth / 2);
          if (startX  < 1) {
            startX = 1;
          }

          if (connectors.length > 0) {

            const childrenIdObj = {}; //// 存取已存在的children的id
            //// console.log('shape.children', shape.children);
            if (diagram.children) {
              searchTree(diagram, node => {
                childrenIdObj[node.id] = node;
                return false;
              });
              //// 自己的内部元素不显示
              //// const shapeType = shape.getTypeName();
              //// if (shapeType !== 'Model' && shapeType !== 'Package') {
              ////   shape.container.children.forEach(node => {
              ////     childrenIdObj[node.id] = node;
              ////   });
              //// } else {
              ////   shape.container.children.forEach(node => {
              ////     const nodeType = node.getTypeName();
              ////     if (nodeType !== 'Block' && nodeType !== 'Package') {
              ////       childrenIdObj[node.id] = node;
              ////     }

              ////   });
              //// }
              //// diagram.children.forEach(child => {
              ////   childrenIdObj[child.graphNode.id] = true;
              //// });
            }

            connectors.reduce((accumulator, connector: ConnentType) => {
              let newShape = null;
              if (!childrenIdObj[connector.element.id]
                && GraphShapeUtil.isValidConnectTarget(connector.graphEdge.getTypeName(), connector.source.getTypeName(), connector.target.getTypeName())) {
                console.log('getGraphElement', connector.element, connector.getGraphElement());
                let childShape = diagram.addChildShape(connector.element.getTypeName(), connector.element, diagram, diagram)[0];
                ResizeUtil.initShape(childShape, accumulator, shape.box.boxY + shape.box.height + CONFIG.verticalSpacing);
                newShape = childShape;
                childrenIdObj[childShape.graphNode.id] = true;
              }
              if (!(childrenIdObj[connector.graphEdge.id] && isSameConnector(childrenIdObj[connector.graphEdge.id], connector.graphEdge, shape))) { //// 线不存在，添加线
                let targetShape = diagram.children.find(item => connector.target === item.container);
                let sourceShape = diagram.children.find(item => connector.source === item.container);
                if (connector.graphEdge.getTypeName() === 'Satisfy') { //// Satisfy的sourceShape需递归查找
                  sourceShape = searchTree(diagram, node => node === connector.getGraphEdge().getSourceConnector().getGraphElement());
                }
                if (targetShape && targetShape.container.id === shape.container.id) { //// 当两个shape来自同一个node时
                  targetShape = shape;
                }
                if (sourceShape && sourceShape.container.id === shape.container.id) { //// 当两个shape来自同一个node时
                  sourceShape = shape;
                }
                if (targetShape && sourceShape) {
                  let edge = diagram.addEdgeShape(null, null, diagram, connector.getGraphEdge(), diagram, sourceShape, targetShape)[0];
                  behaviors.get('SysMLInternalBlockDiagram').displaySatisfyPoint(edge, edge.getTypeName(), diagram, sourceShape);
                  ResizeUtil.initShape(edge);
                }

              }
              if (newShape) {
                return accumulator + newShape.bounds.width + CONFIG.horizontalSpacing;
              } else {
                return accumulator;
              }
            }, startX);

          }
          ResizeUtil.updateAutoFlow(diagram);
          app.$bus.emit("fresh-graph");
        });
    }
  }
}

actions.addAction(new ShowRelatedElementAction());

//// export class GoToDiagramAction implements Action {
////   keyName=''
////   desc="前往画布"
////   bindKey=""
////   onShapeMenuClick(graph:Graph, shape:UmlShape, menuItem:TreeNode){
////     console.log(this.keyName, this.desc);
////     this.run(menuItem.value);

////   }
////   run(diaramId:string|number){
////     app.$bus.emit('diagram-open', { id: diaramId });
////   }
//// }
//// actions.addAction(new GoToDiagramAction());

export class OpenSimulateAction implements Action {
  keyName = 'openSimulate'
  desc = "仿真"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
    if (!shape.graphNode) return;
    this.run(shape.graphNode);

  }

  findActivity(graphNode: GraphNode) {
    const validTypeNames = ["Activity", 'Block', 'StateMachine', 'SysMLParametricDiagram', 'ConstraintBlock'];
    while (graphNode && !validTypeNames.includes(graphNode.getTypeName())) {
      graphNode = graphNode.container;
    }
    return graphNode;

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    this.run(graphNode);

  }

  run(graphNode: GraphNode) {
    const activityNode = this.findActivity(graphNode);
    //// if (!activityNode) {
    ////   console.error('not found activity', activityNode);
    ////   return;
    //// }
    simulation.popup({
      graphNode: activityNode
    }).catch(e => {
      e && console.error(e);
    });

  }
}

actions.addAction(new OpenSimulateAction());

export class OpenSimulateByContextAction implements Action {
  keyName = 'openSimulateByContext'
  desc = "仿真"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
    if (!shape.graphNode) return;
    this.run(shape.graphNode);

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    this.run(graphNode);

  }

  run(graphNode: GraphNode) {
    let id:string;
    if (graphNode.getType() === 'diagram'){
      id = graphNode.container.model?.context()?.id;
    } else {
      id = graphNode.model?.context()?.id;
    }
    if (!id){
      app.$messageBox.error({
        id: 150,
        text: '不存在上下文'
      });
      return;
    }
    let onwer  =  graphHelper.getGraphNodeById(id, app.activeProjectId );
    simulation.popup({
      graphNode: onwer
    }).catch(e => {
      e && console.error(e);
    });

  }
}

actions.addAction(new OpenSimulateByContextAction());

export class CreateIBDAction implements Action {
  keyName = 'createIBD'
  desc = "仿真"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape?: UmlShape) {
    console.log(this.keyName, this.desc);
  }
}

actions.addAction(new CreateIBDAction());

export class InsertSwimlaneAction implements Action {
  keyName = 'insertSwimlane'
  desc = "插入泳道"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape, menuItem: TreeNode) {
    console.log(this.keyName, this.desc);
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new InsertSwimlaneAction());

export class CreateDiagramAction implements Action {
  keyName = 'createDiagram'
  desc = "创建图表"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log(this.keyName, this.desc);
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new CreateDiagramAction());

export class AddPropertyAction implements Action {
  keyName = 'addProperty'
  desc = "添加属性"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape, menuItem: TreeNode) {
    console.log(this.keyName, this.desc);
    this.run(shape.container, menuItem);
    //// shape.addProperty(menuItem.value as string);

  }

  run(graphNode: GraphNode, menuItem: TreeNode) {

    (actions.getAction('openCreateElement') as OpenCreateElementAction).run(graphNode, {
      ...menuItem,
      notSetInEdit: true
    });
    app.$bus.emit('fresh-graph');
    app.$bus.emit('project-modified');
  }
}

actions.addAction(new AddPropertyAction());

export class SetNodeInEditAction implements Action {
  keyName = 'setNodeInEdit'
  desc = "重命名"
  bindKey = ""

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    this.run(graphNode);
  }

  run(graphNode: GraphNode) {
    graphNode.inEdit = true;
    graphNode.expandParentNode();
    app.$bus.emit('project-modified');

  }

}

actions.addAction(new SetNodeInEditAction());

export class OpenCreateElementAction implements Action {
  keyName = 'openCreateElement'
  desc = "新增元素"
  bindKey = ""

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    const typeName = graphNode.getTypeName();
    const list = app.activeProject.configManager.getNestConfig()[typeName];
    const typeNameConfig = app.activeProject.configManager.getTypeNameConfig();
    if (!list) return;
    //// console.log('list', list);
    const menuList = list.filter(i => i.menu)
      .map(item => app.activeProject.configManager.getTreeNodeByTypeName(item.typeName))
      .filter(i => i && (i.type === GraphNodeType.NODE || i.type === GraphNodeType.PORT));

    chooseElement.popup({
      x: window.event.clientX,
      y: window.event.clientY,
      title: '新建元素',
      list: [{ label: '常用元素', children: menuList }]

    }).then((item: TreeNode) => {
      this.run(graphNode, item);

    });

  }

  /**
   *
   * @param graphNode
   * @param menuItem  {label:''//// 默认名称,value:''//// typeName,notSetInEdit:false//// 是否不用立即进入编辑窗台}
   */
  run(graphNode: GraphNode, menuItem: TreeNode) {
    const createdNode = graphNode.addChildNode(menuItem.value as string, app.activeProjectId);
    console.log('createdNode', createdNode, menuItem);
    const newTitle = GraphNodeUtil.getNewChildNodeName(graphNode, '未命名' + menuItem.label);
    const typeName = createdNode.getTypeName();
    if (typeName === 'Package' && app.activeProject.onlineConfig.nodeStatus){
      app.activeProject.onlineConfig.nodeStatus[createdNode.id] = GraphNodeStatus.DEFAULT;
    }
    createdNode.updateName(newTitle);
    treeForEach([createdNode], (node: GraphNode) => {
      GraphNodeUtil.initProperty(node);
    });
    if (!menuItem.notSetInEdit) (actions.getAction('setNodeInEdit') as SetNodeInEditAction).run(createdNode);
    app.$bus.emit('project-modified');
    if (this.shouldFreshGraph(createdNode)) {
      app.$bus.emit('fresh-graph');
    }
    return createdNode;

  }

  shouldFreshGraph(createdNode: GraphNode): boolean {
    const typeName = createdNode.getTypeName();
    //// return GraphNodeUtil.isInstanceOf(typeName, "IProperty") ||  GraphNodeUtil.isInstanceOf(typeName, "IPort");
    return propertyMenuUtil.isProperty(typeName);

  }

}

actions.addAction(new OpenCreateElementAction());

export class OpenCreateDiagramAction implements Action {
  keyName = 'openCreateDiagram'
  desc = "新建图表"
  bindKey = ""

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    chooseElement.popup({
      x: window.event.clientX,
      y: window.event.clientY,
      title: '新建图表',
      list: treeUtil.getDiagramMenu(graphNode.getTypeName())
    }).then((item: TreeNode) => {
      //// treeUtil.createDiagram(item, this.treeData);
      console.log('graphNode', graphNode, item);
      const type = graphNode.getTypeName();
      const value = item.value; //// SysMLParametricDiagram
      if (type === 'Block' && (value === 'SysMLInternalBlockDiagram' || value === 'SysMLParametricDiagram')) { //// 模块创建ibd和par时弹窗

        if (value === 'SysMLInternalBlockDiagram') {
          actions.getAction('createIDBDiagram').run(graphNode);
        } else if (value === 'SysMLParametricDiagram') {
          actions.getAction('createPARDiagram').run(graphNode);
        }
      } else {
        this.run(graphNode, item);
      }

    }).catch(e => e && console.error(e));

  }

  /**
   * 在graphNode创建图，如果graphNode不能容纳此图而其可容纳的子元素可以容纳此图则先创建子元素再创建子元素下的图
   * @param graphNode
   * @param menuItem {label:''//// 默认名称,value:''//// typeName,notSetInEdit:false//// 是否不用立即进入编辑窗台}
   */
  run(graphNode: GraphNode, menuItem: TreeNode) {

    console.log('create diagram', graphNode, menuItem);
    if (menuItem.createParentType) {
      const createParentTypeName = menuItem.createParentType[0];
      if (createParentTypeName) { //// 需要先创建父节点，在创建图表
        const parentGraphNode = graphNode.addChildNode(createParentTypeName, app.activeProjectId);
        const typeNameConfigItem = app.activeProject.configManager.getTypeNameConfigItem(createParentTypeName);
        const newTitle = GraphNodeUtil.getNewChildNodeName(graphNode, graphNode.title ||  '未命名' + typeNameConfigItem.cnName);

        console.log('add node -------------', newTitle);

        parentGraphNode.updateName(newTitle);
        graphNode = parentGraphNode; //// 画布创建在此节点下

      }

    }
    let diagramNode: GraphNode;
    //// diagramNode = graphNode.addChildDiagram(menuItem.value as string, app.activeProjectId);
    switch (menuItem.type) {
      case 'diagram':
        diagramNode = graphNode.addChildDiagram(menuItem.value as string, app.activeProjectId);
        break;
      case 'table':
        diagramNode = graphNode.addChildTable(menuItem.value as string, app.activeProjectId);
        break;
      case 'matrix':
        diagramNode = graphNode.addChildDiagram(menuItem.value as string, app.activeProjectId);
        break;
      case 'relationView':
        diagramNode = graphNode.addChildDiagram(menuItem.value as string, app.activeProjectId);
        break;
      case 'expand':
        diagramNode = graphNode.addChildDiagram(menuItem.value as string, app.activeProjectId);
        break;
      default:
        console.error('未知的type：', menuItem);
        return;
    }

    //// const nameList = graphNode.children ? graphNode.children.map(i => i.title) : [];
    const newTitle = GraphNodeUtil.getNewChildNodeName(graphNode, graphNode.title);

    console.log('add node -------------', newTitle);

    diagramNode.updateName(newTitle);
    //// const diagramNode = treeUtil.createDiagram(menuItem, graphNode);
    if (!menuItem.notSetInEdit) (actions.getAction('setNodeInEdit') as SetNodeInEditAction).run(diagramNode);

    app.$bus.emit('diagram-open', { id: diagramNode.id });
    app.$bus.emit('project-modified');
    if (!app.ui.recentCreateDiagramTypes.includes(menuItem.value)) {
      app.ui.recentCreateDiagramTypes.push(menuItem.value);
    }
    return diagramNode;

  }

}

actions.addAction(new OpenCreateDiagramAction());

export class OpenDiagramAction implements Action {
  keyName = "openDiagram"
  desc = "打开画布" //// 也可以打开表格或矩阵或追溯图
  bindKey = ''
  canOpenTypes = [GraphNodeType.DIAGRAM, GraphNodeType.MATRIX, GraphNodeType.TABLE, GraphNodeType.RELATION_VIEW]

  onShapeMenuClick(graph: Graph, shape: UmlShape, menuItem: TreeNode) {

  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    this.run(graphNode);
  }

  run(graphNode: GraphNode) {
    const typeNameConfigItem = app.activeProject.configManager.getTypeNameConfigItem(graphNode.getTypeName());
    if (typeNameConfigItem && this.canOpenTypes.includes(typeNameConfigItem.type)) {
      app.$bus.emit('diagram-open', { id: graphNode.id });

    }

  }
}

actions.addAction(new OpenDiagramAction());

/**
 * 系统工具栏创建图表
 */
export class OpenCreateDiagramMatrixAction implements Action {
  keyName = 'openCreateDiagramMatrix'
  desc = "新建图表"
  bindKey = ""

  onSysMenuClick(menuItem: TreeNode) {
    let selectedElement = app.selectedElement || app.sysmlModel;
    const nestConfig = app.activeProject.configManager.getNestConfig();
    while (!nestConfig[selectedElement.getTypeName()]) {
      selectedElement = selectedElement.container;
    }
    if (!selectedElement) return;
    elementMatrix.popup({
      x: window.event.clientX,
      y: window.event.clientY,
      title: '新建图表',
      list: treeUtil.getDiagramMenu(selectedElement.getTypeName())
    }).then((item: TreeNode) => {
      //// treeUtil.createDiagram(item, this.treeData);
      this.run(selectedElement, item);

    }).catch(e => e && console.error(e));

  }

  run(graphNode: GraphNode, menuItem: TreeNode) {
    app.$bus.emit('project-modified');
    actions.getAction('openCreateDiagram').run(graphNode, menuItem);
  }
}

actions.addAction(new OpenCreateDiagramMatrixAction());

export class OpenCreateOutRelationAction implements Action {
  keyName = 'openCreateOutRelation'
  desc: '出方向'
  bindKey = ""

  async onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {

    let list = app.activeProject.configManager.getConnectConfig()[graphNode.getTypeName()]?.outgoing;
    if (!list) return;
    const menusList = list.filter(typeName => typeName !== 'Anchor' && typeName !== 'Containment')
      .map(typeName => app.activeProject.configManager.getTreeNodeByTypeName(typeName)).filter(Boolean);
    if (menusList.length === 0) return;

    const edgeTypeName = await chooseElement.popup({
      x: window.event.clientX,
      y: window.event.clientY,
      title: '出方向',
      list: [{ label: '出方向', children: menusList }]

    }).then(item => {
      return item.value;
    }).catch(e => e && console.error(e));
    if (!edgeTypeName) return;
    const res = await selectValue.popup({ selectedElement: app.selectedElement }).catch(err => err && console.error(err));
    console.log({ res });
    if (!res || !res.graphNode) return;
    this.run(edgeTypeName, { source: graphNode, target: res.graphNode });

  }

  run(edgeTypeName: string, option: { source: GraphNode, target: GraphNode }): GraphNode {
    const { source, target } = option;
    const edge = source.addChildEdge(edgeTypeName, source, target, app.activeProjectId);
    GraphNodeUtil.initProperty(edge);
    app.$bus.emit('project-modified');
    return edge;

  }
}

actions.addAction(new OpenCreateOutRelationAction());

export class OpenCreateInRelationAction implements Action {
  keyName = 'openCreateInRelation'
  desc: '入方向'
  bindKey = ""

  async onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    let list = app.activeProject.configManager.getConnectConfig()[graphNode.getTypeName()]?.incoming;
    if (!list) return;
    const menusList = list.filter(typeName => typeName !== 'Anchor' && typeName !== 'Containment')
      .map(typeName => app.activeProject.configManager.getTreeNodeByTypeName(typeName)).filter(Boolean);
    if (menusList.length === 0) return;

    const edgeTypeName = await chooseElement.popup({
      x: window.event.clientX,
      y: window.event.clientY,
      title: '入方向',
      list: [{ label: '入方向', children: menusList }]

    }).then(item => {
      return item.value;
    }).catch(e => e && console.error(e));
    if (!edgeTypeName) return;
    const res = await selectValue.popup({ selectedElement: app.selectedElement }).catch(err => err && console.error(err));
    if (!res || !res.graphNode) return;
    this.run(edgeTypeName, { source: res.graphNode, target: graphNode });

  }

  run(edgeTypeName: string, option: { source: GraphNode, target: GraphNode }): GraphNode {
    app.$bus.emit('project-modified');
    return (actions.getAction('openCreateOutRelation') as OpenCreateOutRelationAction).run(edgeTypeName, option);

  }
}

actions.addAction(new OpenCreateInRelationAction());

export class ExportXmlAction implements Action{
  keyName = 'exportXML';
  desc = '导出项目*.xml';
  bindKey = '';

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    const projectId = app.activeProjectId;
    console.log('项目id', projectId);
    console.log('活跃的节点', graphNode.model);

    localFile.saveAsProjectXML(app.activeProject, false);
  }

}

export class ExportMd3Action implements Action {
  keyName = 'exportMd3';
  desc = '导出项目*.md3';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    localFile.exportPackage(graphNode).catch(err => {
      if (err) {
        app.$messageBox.error({ id: err.info.code });
      }
    });
  }
}
actions.addAction(new ExportMd3Action());

actions.addAction(new ExportXmlAction());

export class ExportMd3pAction implements Action {
  keyName = 'exportMd3p';
  desc = '导出元模型*.md3p';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    const projectId = app.activeProjectId;
    console.log('项目id', projectId);
    console.log('活跃的节点', graphNode.model);
    localFile.exportProfile(graphNode)
      .catch(err => {
        console.log('err', err);
        if (err) {
          app.$messageBox.error({ id: err.info.code });
        }
      });
  }
}

actions.addAction(new ExportMd3pAction());

class ImportMd3pAction implements Action {
  keyName = 'importMd3p';
  desc = '导入元模型*.md3p';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    const projectId = app.activeProjectId;
    console.log('开始导入...');
    localFile.openProfile().then(() => {
      app.$Confirm.popup({
        title: '重启项目',
        subTitle: '重启项目',
        content: '必须要重启项目才能生效，是否立即重启项目？',
        okText: '保存并重启',
        cancelText: '稍后再说'
      })
        .then(res => {
          localFile.reloadProject(app.activeProject).then((project:Project) => {
            app.proxy.projects.set(project.config.id, project);
            localFile.switchToProject(project);
            app.$messageBox.success({ text: '重载成功' });
            project.backupManager.addBackup(SaveType.AUTO);

          });
        })
        .catch((e) => {
          e && console.error(e);
        });
    }) .catch((e) => {
      if (e && e.cancel){
        return;
      } else {
        throw e;

      }
    });
    //// localFile.importProfile(projectId);
  }
}

actions.addAction(new ImportMd3pAction());

class CheckInAction implements Action {
  keyName = 'checkIn';
  desc = '检入';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    //// 判断是否有更新
    let param: any = {
      projectId: app.activeProject.config.id,
      versionId: app.activeProject.onlineConfig.version || '',
    };
    app.$get(API.PLATFORM_SERVICE_VERSION, param)
      .then((res) => {
        if (res.data) { //// 是最新，无需更新
          checkLoading.popup({
            time: 1,
            msg: '正在检入',
            saveFn: this.run
          });
        } else { //// 不是最新，需要更新
          app.$Confirm
            .popup({
              title: '检入',
              content: '当前项目在云端有新的版本，需要更新后才能检入。是否更新？',
              showCheckbox: false,
              status: 'warn',
              cancelText: '取消',
              okText: '更新',
            })
            .then((res) => {
              updateModel.updateProject();
            })
            .catch((e) => {
              e && console.error(e);
            });
        }
      })
      .catch((err) => {
        throw err;
      });
  }
  //// updateProject(){
  ////   app.$get(`platform-service/projects/${app.activeProject.config.id}`, {}, { responseType: 'arraybuffer' })
  ////     .then((res) => {
  ////       const projectId = app.activeProject.config.id;
  ////       proxy.projects.delete(projectId);
  ////       SysMLUtilHelper.removePoolById(projectId);
  ////       MofModelRepositoryHelper.removePool(projectId);
  ////       LocalFileService.loadProjectData(res.data).then((project) => {
  ////         LocalFileService.switchToProject(project);
  ////         app.$messageBox.success({ text: '更新成功' });
  ////       });
  ////     })
  ////     .catch((err) => {
  ////       throw err;
  ////     });
  //// }
  async run() {
    let checkOutId = [{ packageId: app.selectedElement.id, flag: app.selectedElement.status }];
    treeForEach(app.selectedElement.children, (node: GraphNode) => {
      if ((node.getTypeName() === 'Package' && (node.status === GraphNodeStatus.CHECKED_IN || node.status === GraphNodeStatus.CHECKED_OUT)) || node.getTypeName() === 'Model' || (node.getTypeName() === 'Profile' && node.status !== GraphNodeStatus.FROM_PROFILE)) {
        checkOutId.push({ packageId: node.id, flag: node.status });
      }
    });
    let param = {
      projectId: app.activeProject.config.id,
      checkOutId: checkOutId
    };
    const res = await app.$post(API.PLATFORM_SERVICE_COOP_LOCK, param).catch(e => false);
    if (!res) return;
    //// 当前包未被锁定
    const resData = res.data, tableData = [];
    resData.forEach((item) => {
      const node = graphHelper.getGraphNodeById(item.packageId, app.activeProjectId);
      node.status = item.flag;
      if (item.flag === GraphNodeStatus.LOCKED || item.flag === GraphNodeStatus.NO_PERMISSION) {
        const path = node.model.getQualifiedName().replace(/::/g, '/');
        const name = node.title;
        let reason = '';
        if (item.flag === GraphNodeStatus.LOCKED) reason = '已被锁定';
        else if (item.flag === GraphNodeStatus.NO_PERMISSION) reason = '权限不足';
        tableData.push({ name: name, path: path, reason: reason });
      }
    });
    //// 如果子包有锁定，显示无法检入项弹框
    if (tableData.length) {
      unablecheckInPackageModal
        .popup({
          tableData: tableData,
        })
        .catch((e) => {
          e && console.error(e);
        });
    } else {
      //// 如果子包没有锁定，就检入成功
      app.$Confirm
        .popup({
          title: '检入',
          content: '检入成功',
          showCheckbox: false,
          status: 'success',
          cancelText: '',
        }).catch((e) => {
          e && console.error(e);
        });
    }
  }
}

actions.addAction(new CheckInAction());

class CheckOutAction implements Action {
  keyName = 'checkOut';
  desc = '检出';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    //// 若无更改，直接检出
    if (!app.activeProject.onlineConfig.needSubmit){
      checkLoading.popup({
        time: 1,
        content: '正在检出',
        saveFn: this.run
      });
    } else { //// 若有更改，弹出选择
      app.$Confirm
        .popup({
          title: '检出',
          content: '当前包下有未提交的更改',
          subContent: '请选择如何处理更改',
          showCheckbox: false,
          status: 'warn',
          cancelText: '取消',
          //// centerBtnText: '丢弃更改',
          okText: '提交更改',
          onClickOk: (vm) => {
            vm.handleCancel();
            console.log(submitUpdate);
            submitUpdate.openSubmitUpdateModal();
          }
        })
        .then((res) => {
          checkLoading.popup({
            time: 1,
            content: '正在检出',
            saveFn: this.run
          });
        })
        .catch((e) => {
          e && console.error(e);
        });
    }
  }

  run() {
    let checkOutId = [{ packageId: app.selectedElement.id, flag: app.selectedElement.status }];
    treeForEach(app.selectedElement.children, (node: GraphNode) => {
      if (node.getTypeName() === 'Package' || node.getTypeName() === 'Model' || (node.getTypeName() === 'Profile' && node.status !== GraphNodeStatus.FROM_PROFILE)) {
        if ([0, 1, 3, 4].includes(node.status)){
          checkOutId.push({ packageId: node.id, flag: node.status });
        }
      }
    });
    const param = {
      projectId: app.activeProject.config.id,
      checkOutId: checkOutId
    };
    app.$post(API.PLATFORM_SERVICE_COOP_UNLOCK, param).then((res) => {
      const resData = res.data;
      //// 重置flag
      resData.forEach((item) => {
        const node = graphHelper.getGraphNodeById(item.packageId, app.activeProjectId);
        node.status = item.flag;
      });
      app.$Confirm
        .popup({
          title: '检出',
          content: '检出成功',
          showCheckbox: false,
          status: 'success',
          cancelText: '',
        }).then((res) => {
          graphNodeStatusFresher.freshNodeStatus();
        })
        .catch((e) => {
          e && console.error(e);
        });
    }).catch((err) => {
      app.$Confirm
        .popup({
          title: '检出',
          content: '检出失败',
          subContent: err.message,
          showCheckbox: false,
          status: 'error',
          cancelText: '',
        })
        .catch((e) => {
          e && console.error(e);
        });
    });
  }
}

actions.addAction(new CheckOutAction());

class ImportMd3Action implements Action {
  keyName = 'importProjectMd3';
  desc = '导入项目*.md3';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    console.log('开始导入...');
    //// const x2js = new X2JS();
    //// const project = x2js.xml2js(graphNode);
    localFile.importProject().then((project) => {
      app.$Confirm.popup({
        title: '导入项目',
        subTitle: '导入项目',
        content: '导入项目后,需要重新加载导入合并之后的项目,是否确认？',
        okText: '确认',
        cancelText: '稍后再说'
      })
        .then(res => {
          console.log('project-------------------', project);
          this.run(project, graphNode);
        })
        .catch((e) => {
          e && console.error(e);
        });
    }).catch(e => {
      if (e && e.cancel){
        return;
      } else {
        throw e;

      }
    });
  }

  run(project: Project, graphNode: GraphNode): any {
    const projectId = app.activeProjectId;
    const childProjectId = project.config.id;
    if (childProjectId == projectId) {
      app.$messageBox.error({ text: '不能导入相同的项目' });
      console.log('error with same projectId');
    } else {
      const parentModel = graphNode.model;
      const baseDependencies = app.activeProject.config.dependencies;
      const ids = baseDependencies.map(it => it.dependencyId);
      const paths = baseDependencies.map(it => it.dependencyPath);
      const childDependencies = project.config.dependencies;
      childDependencies.forEach(it => {
        if (!ids.includes(it.dependencyId) && !paths.includes(it.dependencyPath)) {
          baseDependencies.push(it);
        }
      });
      app.activeProject.config.dependencies = baseDependencies;
      const childModel = project.metadata.sysml.model;
      const projectName = project.config.projectName;
      SysMLUtilHelper.projectImport(parentModel, childModel, projectName, projectId, childProjectId);
      localFile.reloadProject(app.activeProject).then((project:Project) => {
        app.proxy.projects.set(project.config.id, project);
        localFile.switchToProject(project);
        app.$messageBox.success({ text: '导入项目成功' });
        project.backupManager.addBackup(SaveType.AUTO);
        console.log(project);
      });
    }
  }
}

actions.addAction(new ImportMd3Action());

class ImportXMLAction implements Action {
  keyName = 'importProjectXML';
  desc = '导入项目*.xml';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    console.log('开始导入xml...');
    localFile.importProjectXML().then((project) => {
      app.$Confirm.popup({
        title: '导入项目',
        subTitle: '导入项目',
        content: '导入项目后,需要重新加载导入合并之后的项目,是否确认？',
        okText: '确认',
        cancelText: '稍后再说'
      })
        .then(res => {
          this.run(project, graphNode);
        })
        .catch((e) => {
          e && console.error(e);
        });
    }).catch(e => {
      if (e && e.cancel){
        return;
      } else {
        throw e;

      }
    });
  }

  run(project: Project, graphNode: GraphNode): any {
    const projectId = app.activeProjectId;
    const childProjectId = project.config.id;
    let XMLprojectIdList = app.activeProject.config.XMLprojectIdList;
    if (!XMLprojectIdList) {
      XMLprojectIdList = app.activeProject.config.XMLprojectIdList = [];
    }
    if (childProjectId == projectId || XMLprojectIdList.includes(childProjectId)) {
      app.$messageBox.error({ text: '不能导入相同的项目' });
      console.log('error with same projectId');
    } else {
      const parentModel = graphNode.model;
      const baseDependencies = app.activeProject.config.dependencies;
      const ids = baseDependencies.map(it => it.dependencyId);
      const paths = baseDependencies.map(it => it.dependencyPath);
      const childDependencies = project.config.dependencies;
      childDependencies.forEach(it => {
        if (!ids.includes(it.dependencyId) && !paths.includes(it.dependencyPath)) {
          baseDependencies.push(it);
        }
      });
      app.activeProject.config.dependencies = baseDependencies;
      XMLprojectIdList.push(childProjectId);
      const childModel = project.metadata.sysml.model;
      const projectName = project.config.projectName;
      SysMLUtilHelper.projectImport(parentModel, childModel, projectName, projectId, childProjectId);
      localFile.reloadProject(app.activeProject).then((project:Project) => {
        app.proxy.projects.set(project.config.id, project);
        localFile.switchToProject(project);
        app.$messageBox.success({ text: '导入项目成功' });
        project.backupManager.addBackup(SaveType.AUTO);
        console.log(project);
      });
    }
  }
}

actions.addAction(new ImportXMLAction());

class SyncReq implements Action {
  keyName = 'syncReq';
  desc = '同步需求';
  bindKey = '';

  /**
   * @param graphNode 点击的树节点
   * @param menuItem
   * 树上触发Action
   */
  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode): void {
    syncReqModal
      .popup()
      .catch((err) => {
        err && console.error(err);

      });
  }
}
actions.addAction(new SyncReq());
class SetProperty implements SetPropertyAction {
  keyName = 'setProperty';
  desc = '设置属性';
  bindKey = '';

  run(property: any, graphNode: GraphNode, currentIds = [], shape?: UmlShape): any {
    console.log('selectMutiple', property);
    selectMutiple.popup({
      currentIds,
      filterCondtion: property.config.moreBtnCondition,
      propertyKey: property.fromStereotype ?  property.property : property.config.key,
    }).then(res => {
      console.log(res, 'res');
      const modelArr = res.map(i => i.graphNode.model);
      const graphNodeArr = res.map(i => i.graphNode);
      PropertyUtil.updateRow(modelArr, property, graphNode, graphNodeArr);
      if (graphNode.getTypeName() === 'Instance' && shape) {
        this.setInstanceImage(shape, graphNodeArr[0]);
        graphNode.refreshCompartment();
      }
    }).catch(e => {
      //// e && console.error(e);
      if (e){
        throw e;
      }
    });
  }

  /**
   * 设置instance的右上角图标
   * @param shape target的shape
   * @param graphNode 源的node
   */
  setInstanceImage(shape: UmlShape, graphNode: GraphNode): void {
    const instanceNode = shape.container;
    let boxKeys = graphHelper.getBoxConfigByTypeName(instanceNode.getTypeName());
    const shapeKeys = boxKeys.keys.toArray()[2];
    const imageShape = shape.children.filter(item => item.typeKey === shapeKeys)[0];
    const req = /image=.*;/;
    const style = imageShape.box.style;
    if (!graphNode) {
      imageShape.box.style = style.replace(req, '');
    } else {
      let iconPath = graphNode.iconPath;
      if (iconPath.includes('base64')) {
        iconPath = iconPath.replace(/;/, '');
      };
      if (req.test(style)) {
        imageShape.box.style = style.replace(req, `image=${iconPath};`);
      } else {
        imageShape.box.style = style + `image=${iconPath};`;
      }
    }

    //// console.log('style', style, imageShape.box.style);
  }
}

actions.addAction(new SetProperty());
export class SaveDefaultValueAction implements Action {
  keyName = 'saveDefaultValue'
  desc = "设置默认值"
  bindKey = ""

  onShapeMenuClick(graph: Graph, shape: UmlShape) {
    console.log('shape.container', shape.container);
    shape.container.saveDefaultValue();
  }

  onTreeMenuClick(graphNode: GraphNode, menuItem: TreeNode) {
    graphNode.saveDefaultValue();
  }

  run(shape: UmlShape) {

  }
}
actions.addAction(new SaveDefaultValueAction());

actions.createEvents();

actions.addKeyboardListener();

